package com.fingard.util;

import com.fingard.FGBiz;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.RequestEntity;
import org.apache.commons.httpclient.methods.StringRequestEntity;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.SSLContext;
import javax.net.ssl.X509TrustManager;
import javax.servlet.http.HttpServletRequest;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.*;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


public class HttpClientUtil {

    private static final Logger logger = LoggerFactory.getLogger(HttpClientUtil.class);
        private static final String PROPERTY_TYPE = "Content-Type";
    private static final String PROPERTY = "application/x-www-form-urlencoded";

    protected static HttpsTrustManager httpsTrustManager = new HttpsTrustManager();


    // https prefix
    protected static final String HTTPS = "https";

    protected static int maxConnectionSeconds = 1000;

    protected static final int MS_TO_S_UNIT = 1000;

    /**
     * <p>Title: execute</p>
     * <p>Description: </p>
     *
     * @param url    http://jk-bis-stg.dmzstg.pingan.com.cn:7080/bis/service
     * @param xmlStr
     * @return
     */
    public static String execute(String url, String xmlStr) throws Exception {

        HttpURLConnection conn = null;
        try {
            conn = (HttpURLConnection) (new URL(url).openConnection());
        } catch (MalformedURLException e) {
            // TODO Auto-generated catch block
            throw e;
        } catch (IOException e) {
            // TODO Auto-generated catch block
            throw e;
        }

        DataOutputStream out = null;
        try {
            conn.setConnectTimeout(120 * 1000);
            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setRequestMethod("POST");
            conn.setUseCaches(false);
            conn.setRequestProperty(PROPERTY_TYPE, PROPERTY);
            conn.connect();

            byte[] data = xmlStr.getBytes();
            out = new DataOutputStream(conn.getOutputStream());
            out.write(org.apache.commons.codec.binary.Base64
                    .encodeBase64(data));
            out.flush();
            out.close();
            logger.info(conn.getResponseCode() + ">>"
                    + conn.getResponseMessage());

            byte[] bytes = org.apache.commons.codec.binary.Base64
                    .decodeBase64(toByteArray(conn.getInputStream()));

            String ret = "";
            if (bytes == null || bytes.length == 0) {
                System.out.println("time out");
            } else {
                // 返回乱码用这个
                ret = new String(bytes, "UTF-8");
                logger.info(ret);
            }
            conn.disconnect();
            return ret;
        } catch (Exception e) {
            throw e;
        }
    }
    
    public static String executeXml(String url, String xmlStr) throws Exception {

    	HttpClient httpclient = new HttpClient();
        PostMethod post = new PostMethod(url);
        String info = null;
        try {
	            RequestEntity entity = new StringRequestEntity(xmlStr, "text/plain",
	                    "GBK");
	            post.setRequestEntity(entity);
	            httpclient.executeMethod(post);
	            int code = post.getStatusCode();
	            if (code == HttpStatus.SC_OK)
	                info = new String(post.getResponseBodyAsString());
        } catch (Exception ex) {
	            ex.printStackTrace();
        } finally {
	            post.releaseConnection();
        }
        return info;
    }


    public static final byte[] input2byte(InputStream inStream)
            throws IOException {
        ByteArrayOutputStream swapStream = new ByteArrayOutputStream();
        byte[] buff = new byte[100];
        int rc = 0;
        while ((rc = inStream.read(buff, 0, 100)) > 0) {
            swapStream.write(buff, 0, rc);
        }
        byte[] in2b = swapStream.toByteArray();
        return in2b;
    }

    public static byte[] toByteArray(InputStream is) throws IOException {
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        byte[] data = new byte[4096];
        int len;
        while ((len = is.read(data)) != -1) {
            out.write(data, 0, len);
            out.flush();
        }
        return out.toByteArray();
    }

    public static String executeGet(String scheme, String host, int port, String path, Map<String, String> paramMap) throws IOException {
        CloseableHttpClient httpClient = HttpClients.createDefault();

        List<NameValuePair> parameters = new ArrayList<NameValuePair>();

        for (Map.Entry<String, String> entry : paramMap.entrySet()) {

            parameters.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
        }

        String strResult = null;

        try {
            URI uri = new URIBuilder()
                    .setScheme(scheme)
                    .setHost(host)
                    .setPort(port)
                    .setPath(path).setParameters(parameters).build();

            HttpGet httpGet = new HttpGet(uri);

            HttpResponse httpResponse = httpClient.execute(httpGet);

            if (httpResponse.getStatusLine().getStatusCode() == 200) {
                strResult = EntityUtils.toString(httpResponse.getEntity(),"UTF-8");//获得返回的结果
                System.out.println(strResult);
            }
        } catch (URISyntaxException e) {
            e.printStackTrace();
        } finally {
            try {
                httpClient.close();//释放资源
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return strResult;

    }

    public static String executeGet(String url) throws IOException {
        CloseableHttpClient httpClient = HttpClients.createDefault();
        HttpGet httpGet = new HttpGet(url);
        String strResult = null;
        try {
            HttpResponse httpResponse = httpClient.execute(httpGet);

            if (httpResponse.getStatusLine().getStatusCode() == 200) {
                strResult = EntityUtils.toString(httpResponse.getEntity(), "UTF-8");//获得返回的结果
                System.out.println(strResult);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                httpClient.close();//释放资源
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return strResult;
    }

    public static String executePost(String uri, Map<String, String> paramMap,String charset) throws IOException {

        // CloseableHttpClient httpClient = HttpClients.createDefault();

        CloseableHttpClient httpClient = retrieveHttpClient(uri);

        HttpPost httpPost = new HttpPost(uri);

        List<NameValuePair> parameters = new ArrayList<NameValuePair>();

        for (Map.Entry<String, String> entry : paramMap.entrySet()) {

            parameters.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
        }

        String strResult = null;

        try {
            httpPost.setEntity(new UrlEncodedFormEntity(parameters, charset));

            HttpResponse httpResponse = httpClient.execute(httpPost);

            logger.info("responseCode:{}",httpResponse.getStatusLine().getStatusCode());

            if (httpResponse.getStatusLine().getStatusCode() == 200) {
                strResult = EntityUtils.toString(httpResponse.getEntity(),charset);//获得返回的结果
                logger.info("post请求返回信息为：{}",strResult);
            }

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                httpClient.close();//释放资源
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return strResult;
    }

    public static String executeJsonPost(String uri, String jsonStr) throws IOException {

        // CloseableHttpClient httpClient = HttpClients.createDefault();

        CloseableHttpClient httpClient = retrieveHttpClient(uri);

        HttpPost httpPost = new HttpPost(uri);

        List<NameValuePair> parameters = new ArrayList<NameValuePair>();
        //
        StringEntity se = new StringEntity(jsonStr);

        se.setContentType("text/json");

        se.setContentEncoding(new BasicHeader(HTTP.CONTENT_TYPE, "application/json;charset=utf-8"));

        String strResult = null;

        try {
            httpPost.setEntity(se);

            HttpResponse httpResponse = httpClient.execute(httpPost);

            logger.info("responseCode:{}",httpResponse.getStatusLine().getStatusCode());

            if (httpResponse.getStatusLine().getStatusCode() == 200) {
                //获得返回的结果
                strResult = EntityUtils.toString(httpResponse.getEntity(),"UTF-8");
                logger.info("post请求返回信息为：{}",strResult);
            }

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                httpClient.close();//释放资源
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return strResult;
    }


    protected static boolean isHttps(String url) {
        return url.toLowerCase().startsWith(HTTPS);
    }

    private static RequestConfig requestConfig() {
        final int maxConnMillSeconds = maxConnectionSeconds * MS_TO_S_UNIT;
        RequestConfig.Builder rBuilder = RequestConfig.custom();
        boolean enableProxy = FGBiz.dspCenter.dspSet.enableProxy;
        if (enableProxy) {
            String proxyIP = FGBiz.dspCenter.dspSet.proxyIP;
            int proxyPort = Integer.parseInt(FGBiz.dspCenter.dspSet.proxyPort);
            HttpHost proxy = new HttpHost(proxyIP, proxyPort,"http");
            rBuilder.setProxy(proxy);
        }
        return rBuilder.setSocketTimeout(maxConnMillSeconds)
                .setConnectTimeout(maxConnMillSeconds).build();
    }

    protected static CloseableHttpClient retrieveHttpClient(String url) {
        final RequestConfig requestConfig = requestConfig();
        if (isHttps(url)) {
            // Support SSL
            SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(
                    createSSLContext());
            return HttpClients.custom().setDefaultRequestConfig(requestConfig)
                    .setSSLSocketFactory(sslConnectionSocketFactory).build();
        } else {
            return HttpClients.custom().setDefaultRequestConfig(requestConfig)
                    .build();
        }
    }

    private static SSLContext createSSLContext() {
        try {
            SSLContext sslContext= SSLContexts.custom().useProtocol("TLSv1.2").build();
            //SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
            sslContext.init(null,
                    new HttpsTrustManager[] { httpsTrustManager }, null);
            return sslContext;
        } catch (Exception e) {
            throw new IllegalStateException("Create SSLContext error", e);
        }
    }


    /**
     * Default X509TrustManager implement
     */
    private static class HttpsTrustManager implements X509TrustManager {

        @Override
        public void checkClientTrusted(X509Certificate[] x509Certificates,
                                       String s) throws CertificateException {
            // ignore
        }

        @Override
        public void checkServerTrusted(X509Certificate[] x509Certificates,
                                       String s) throws CertificateException {
            // ignore
        }

        @Override
        public X509Certificate[] getAcceptedIssuers() {
            return null;
        }
    }


    public static void main(String[] args) {

        String uri="https://test-mzone.stg.yqb.com/mzone-http/bind_card/bind_card_entrance_for_outer";
        Map<String, String> map = new HashMap<String, String>();
        map.put("cancelUrl", "");
        map.put("requestMsg","qpiPPL38yc/j/Ip4P0z9L56xEHf38GfbDNqUeMUyHtolsRvkBpTf3YDENN+ytrQjYu64wKiX7oReFwAsmRGLYbr0lCMLNGhHdfOoD5trDRfGXxGzhy3GB5hwu3O07h8LXWyGqWTFHXy+4GubLVp9TAWU/moGbf/Vj8WxiV9f5BFz/KKU1ATqLTCAnqB6RHTJqS0+lanJKHByYJFDjMHNotZZlh1RIFy95Q1CCZx8kMFRVprOmPj4YtBgqs0Ac5+VLL0JwshPVqQdvszyHMoa+mKn6abtjIOhH/4Go2GdfwpobXGun/xAANVdWFRLHCH0PYjjJ6tZdttxlYngdY1BTQ==");

        try {
            String res = HttpClientUtil.executePost(uri, map, "UTF-8");
            System.out.println(res);

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static String getIpAddr(Map<String,String> request) {
        String ip = request.get("x-forwarded-for") == null ? null:request.get("x-forwarded-for").toString();
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.get("Proxy-Client-IP") == null ? null:request.get("Proxy-Client-IP").toString();
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.get("WL-Proxy-Client-IP") == null ? null:request.get("WL-Proxy-Client-IP").toString();
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            String addressIP = request.get("Remote Address")  == null ? null:request.get("Remote Address").toString();;
            if(addressIP!=null && addressIP.contains(";")){
                ip = addressIP.split(";")[0];
            }
        }
        return ip;
    }

}
